home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / wmv12s.zip / NORMAL.C < prev    next >
Text File  |  1993-01-04  |  10KB  |  430 lines

  1. /* The normal routine "normalizes" a given path name to this form:
  2. ** drv:\id\id\id...\id
  3. ** so that two identical directory/file will yield the same normalized
  4. ** path regardless of how the user typed it in
  5. ** E.g.
  6. **     a:\x\y
  7. **   and a:\X\Y\.
  8. **  both yield A:\X\Y
  9. **
  10. ** In addition, the later one would also set the flag "dir" indicating
  11. ** that the user specified it as an directory.
  12. **
  13. ** Written by Peter Wu @ Faculty Support Center @ Univ. of Wisconsin
  14. ** 7/14/86
  15. */
  16. #define LINT_ARGS
  17.  
  18. #define T_ID1 1  /* id without period */
  19. #define T_ID2 2  /* id with period */
  20. #define T_DOT 3  /* '.' */
  21. #define T_DD  4
  22. #define T_BS  5
  23. #define T_COL 6
  24. #define T_NUL 0
  25.  
  26. #define PLEN 200
  27.  
  28. #include "dta.h"
  29. #include <dos.h>
  30. #include <string.h>
  31. #include <conio.h>
  32.  
  33. char *insert();
  34.  
  35. index(str,c) /* first occurence of c in str */
  36. char *str, c;
  37. {
  38.   char *i, d;
  39.  
  40.   i = str;
  41.   d = *i;
  42.   while (d != '\0') {
  43.     if (d == c) {
  44.       return i - str;
  45.     }
  46.     i++;
  47.     d = *i;
  48.   }
  49.   return -1;
  50. }
  51.  
  52. char lastc(str)  /* return last character of the string */
  53. register char *str;
  54. {
  55.   if (*str == '\0') {
  56.     return '\0';
  57.   }
  58.  
  59.   do {
  60.     str++;
  61.   } while (*str != '\0');
  62.  
  63.   return *(str-1);
  64. }
  65.  
  66. normal(path)  /* normalize a path */
  67. char *path;
  68. {
  69.   char work1[PLEN], work2[PLEN], token[13], token2[13], *ptr;
  70.   int i, drv, marker, t, ftype, t2;
  71.  
  72.   /* first make the path a complete path (include drive, and root) */
  73.   i = index(path, ':');  /* search for ':' */
  74.   if (i < 0) {    /* no drive specification */
  75.     if (*path == '\\') {  /* start from root */
  76.       work1[0] = '@' + drive();  /* default disk */
  77.       work1[1] = ':';
  78.       work1[2] = '\0';
  79.       strcat(work1, path);  /* now we have full path */
  80.     } else {  /* no drive and no root */
  81.       current(0,work1);  /* get current drive and path */
  82.       strcat(work1, path);  /* now we have full path */
  83.     }
  84.   } else {  /* has drive specification */
  85.     if (path[i+1] != '\\') {  /* but no root, so insert current path */
  86.       drv = toupper(path[i-1]) - '@';  /* get drive number */
  87.       current(drv,work1);  /* put down drive and path */
  88.       strcat(work1, path+i+1);    /* now we have full path */
  89.     } else {  /* nothing to change */
  90.       strcpy(work1,path);
  91.     }
  92.   }
  93.  
  94. #ifdef debug
  95.   printf("full path is %s\n", work1);
  96. #endif
  97.  
  98.   /* now we have full path in work, but we need to normalize it to get rid
  99.   ** of .. and .
  100.   */
  101.   marker = -2;
  102.   work2[PLEN-1] = '\0';  /* this is where we accumulate result backwards */
  103.   ptr = work2 + PLEN - 1;  /* point to first char */
  104.   ftype = -1;  /* -1=init, 0=unknown,  A_DIR=dir */
  105.  
  106.   do {
  107.     t = scan(work1,&marker,token);
  108. #ifdef debug
  109.     printf("ptr is %s so far, and t=%d\n", ptr, t);
  110. #endif
  111.     switch (t) {
  112.  
  113.       case T_ID1:
  114.       case T_ID2:
  115.     ptr = insert(token, ptr);
  116.     if (ftype == -1) {
  117.       ftype = 0;  /* this could be a file or a directory */
  118.     }
  119.     break;
  120.  
  121. #ifdef ha
  122.       case T_ID2:
  123.     if (ftype == -1) {
  124.       ptr = insert(token, ptr);
  125.       ftype = 0;  /* this could be file or a directory */
  126.     } else {
  127.       putn("invalid sub-directory name \"", token, "\"\n\015",0);
  128.       exit(1);
  129.     }
  130.     break;
  131. #endif
  132.  
  133.       case T_DD:
  134.     t2 = scan(work1,&marker,token);  /* see what's in front of .. */
  135.     if (t2 != T_BS) {
  136.       cputs("incorrect use of \"..\" in path name\n\015");
  137.       exit(1);
  138.     }
  139.     /* now delete \id\.. */
  140.     t2 = scan(work1,&marker,token);  /* read the id (hopefully) */
  141.     if (t2 != T_ID1) {
  142.       if (t2 == T_COL) {  /* A:\.. is not permitted */
  143.         cputs("sorry, but root directory has no parent\n\015");
  144.         exit(1);
  145.       } else {  /* what could t2 be? */
  146.         cputs("missing directory name in front of \"\\..\"\n\015");
  147.         exit(1);
  148.       }
  149.     }
  150.     t2 = scan(work1,&marker,token2);  /* read the '\' */
  151.     if (t2 != T_BS) {  /* can this ever happen? */
  152.       putn("missing \"\\\" before \"", token, "\" in path\n\015",0);
  153.       exit(1);
  154.     }
  155.  
  156.     /* a:\id\.. should yield a:\ not a:
  157.     ** a:\id1\..\id2 should yield a:\id2
  158.     ** this is taken care of somewhere else
  159.     */
  160.  
  161.     /* ok, \id\.. deleted */
  162.     if (ftype == -1) {
  163.       ftype = A_DIR;  /* this has to be a directory */
  164.     }
  165.     break;
  166.  
  167.       case T_DOT:
  168.     t2 = scan(work1,&marker,token);  /* read the '\' */
  169.     if (t2 != T_BS) {  /* is this error possible? */
  170.       cputs("missing \"\\\" in front of \".\"\n\015");
  171.       exit(1);
  172.     }
  173.     if (ftype == -1) {
  174.       ftype = A_DIR;  /* this has to be a directory */
  175.     }
  176.     /* special case is "a:\." we want this to turn into "A:\" and
  177.     ** not "A:"
  178.     */
  179.     break;
  180.  
  181.       case T_BS:
  182.     ptr = insert("\\", ptr);
  183.     break;
  184.  
  185.       case T_COL:
  186.     ptr = insert(":", ptr);
  187.     break;
  188.     }
  189.   } while (t != T_NUL);
  190.  
  191.   if (lastc(ptr) == ':') {  /* special case like a: */
  192.     strcat(ptr,"\\");
  193.   }
  194.   strcpy(path,ptr);  /* copy normalized path back */
  195.   return ftype;
  196. }
  197.  
  198. char *insert(str1,str2)  /* insert str1 in front of str2 */
  199. char *str1, *str2;
  200. {
  201.   int i;
  202.  
  203.   i = strlen(str1);
  204.   return strncpy(str2 - i, str1, i);
  205. }
  206.  
  207. scan(path,marker,tstr) /* return tokens backwards */
  208. char *path, *tstr;
  209. int *marker;
  210. {
  211.   char c, d;
  212.  
  213.   if (*marker == -2) {    /* signal new scan */
  214.     *marker = strlen(path) - 1;
  215.   }
  216.  
  217.   if (*marker == -1) {
  218.     return T_NUL;  /* end of string */
  219.   }
  220.  
  221.   c = path[*marker];
  222.   if ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ) {
  223.     return collect_id(tstr, path, marker);
  224.   }
  225.  
  226.   switch (c) {
  227.     case '.':
  228.       if (*marker == 0) {
  229.     *marker = -1;
  230.     return T_DOT;
  231.       } else {
  232.     d = path[*marker - 1];
  233.     if (d == '.') {
  234.       *marker -= 2;
  235.       return T_DD;
  236.     } else {
  237.       if ((d == '\\') || (d == ':')) {
  238.         (*marker)--;
  239.         return T_DOT;
  240.       } else {  /* must be an id with trailing dot */
  241.         return collect_id(tstr, path, marker);
  242.       }
  243.     }
  244.       }
  245.       cputs("how do I get here?\n\015");
  246.       error("scan", 0);
  247.  
  248.     case '\\':
  249.       (*marker)--;
  250.       return T_BS;
  251.  
  252.     case ':':
  253.       (*marker)--;
  254.       return T_COL;
  255.  
  256.     default:
  257.       return collect_id(tstr, path, marker);  /* non-alpha ID */
  258.   }
  259. }
  260.  
  261. check_fn(fn)  /* look for invalid characters in file name */
  262. char *fn;
  263. {
  264.   char c, *s;
  265.  
  266.   s = fn;
  267.   while((c= *s) != '\0') {
  268.     if ((c < 32) || (index("\"[]|<>+=;,/",c) > -1)) {
  269.       cputs("invalid character '"); putch(c);
  270.       putn("' in file/sub-directory name \"", fn, "\"", 0);
  271.       exit(1);
  272.     }
  273.     s++;
  274.   }
  275. }
  276.  
  277. collect_id(tstr, path, marker)
  278. char *tstr, *path;
  279. int *marker;
  280. {
  281.   char c, id[13];
  282.   int flag, i;
  283.  
  284.   id[13] = '\0';
  285.   i = 12;
  286.   flag = T_ID1;  /* no period in file name */
  287.   do {
  288.     c = path[*marker];
  289.  
  290.     if (c == '.') {  /* indicate there's period in the file name */
  291.       flag = T_ID2;
  292.     } else {
  293.       c = toupper(c);
  294.       if ((c == '\\') || (c == ':')) {  /* end of file name */
  295.     strncpy(tstr, id+i+1, 13);
  296.     check_fn(tstr);
  297.     return flag;
  298.       }
  299.     }
  300.  
  301.     id[i] = c;
  302.     (*marker)--;
  303.     if (*marker < 0) {
  304.       strncpy(tstr, id+i, 13);
  305.       check_fn(tstr);
  306.       return flag;
  307.     }
  308.     i--;
  309.   } while (i >= 0);
  310.  
  311.   putn("file/sub-directory name \"...", id, "\" too long\n\015", 0);
  312.   exit(1);
  313. }
  314.  
  315. drive()  /* returns current drive number 1=A 2=B */
  316. {
  317.   return (char) bdos(0x19, 0, 0) + 1;
  318. }
  319.  
  320. current(drv,cpath)  /* returns current path "drv:\id\..\id on drv */
  321. char *cpath;
  322. int drv;
  323. {
  324.   union REGS inregs, outregs;
  325.   char tmp[64];
  326.  
  327.   inregs.h.ah = 0x47;  /* get current path */
  328.   inregs.x.si = (int) tmp;
  329.   inregs.h.dl = drv;  /* drive number 0=default, 1=A, 2=B */
  330.   intdos(&inregs, &outregs);
  331.   if (drv == 0) {
  332.     drv = drive();
  333.   }
  334.   if (outregs.x.cflag) {
  335.     cputs("cannot find current path on drive "); putch('@'+drv);
  336.     cputs(":\n\015");
  337.     error("current", 0);
  338.   } else {
  339.     cpath[0] = '@' + drv;
  340.     cpath[1] = ':';
  341.     cpath[2] = '\\';
  342.     cpath[3] = '\0';
  343.     if (*tmp != '\0') {  /* if not root directory, then append path */
  344.       strcat(cpath,tmp);
  345.       strcat(cpath,"\\");
  346.     }
  347.   }
  348. }
  349.  
  350. catpath(path, name)  /* concatenate name to path, adding \ when neccessary */
  351. char *path, *name;
  352. {
  353.   if (path[strlen(path)-1] != '\\') {
  354.     strcat(path, "\\");
  355.   }
  356.   strcat(path, name);
  357. }
  358.  
  359. chopath(path)  /* chop off the last portion of a path */
  360. char *path;
  361. {
  362.   char *tmp;
  363.  
  364.   tmp = strrchr(path, '\\');
  365.   if (tmp == (char *)0) {
  366.     putn("can't find '\\' in ", path, "\n\015");
  367.     error("chopath", 0);
  368.   }
  369.   if (*(tmp-1) == ':') {  /* special case for root */
  370.     *(tmp+1) = '\0';
  371.   } else {
  372.     *tmp = '\0';
  373.   }
  374. }
  375.  
  376. #define A_INT 0x80    /* interactive flag */
  377.  
  378. /* extract the file-type specifier from the given path.
  379. ** E.g.  x/f becomes x with file type,
  380. **     animal\dog/d becomes animal\dog with sub-directory type,
  381. **     *./f becomes *. with file type
  382. **     *.* becomes *.* with no type
  383. **     *./i becomes interactive (i.e. prompts for y/n for each file)
  384. */
  385. extype(path)
  386. char *path;
  387. {
  388.   char *s;
  389.   int type;
  390.  
  391.   s = strrchr(path,'/');  /* find last '/' */
  392.   if (s == (char *) 0) {  /* no type specified */
  393.     return 0;
  394.   }
  395.  
  396.   type = 0;
  397.   *s = '\0';
  398.   for (++s; *s != '\0'; s++) {  /* start scanning after the '/' */
  399.     switch (*s) {
  400.       case 'f':
  401.       case 'F':
  402.     type |= A_FIL;
  403.     break;
  404.  
  405.       case 'd':
  406.       case 'D':
  407.     type |= A_DIR;
  408.     break;
  409.  
  410.       case 'h':
  411.       case 'H':
  412.     type |= A_HID;    /* search for hidden files */
  413.     break;
  414.  
  415.       case 'i':
  416.       case 'I':
  417.     type |= A_INT;    /* requires user's confirmation for each file */
  418.     break;
  419.  
  420.       default:
  421.     cputs("unrecognized file attribute '"); putch(*s);
  422.     putn("' in path \"", path, "\"\n\015",
  423. "valid attributes are f, d, h, i (for file, directory, hidden, interac)\n\015",
  424.  0);
  425.     exit(1); /* maybe the user doesn't know what he/she's doing */
  426.     }
  427.   }
  428.   return type;
  429. }
  430.